package cd.zhixuan.utils.task;

import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
 * 读取字节流数据
 */
public class ReadByteAdapterAbs implements ReadByteAdapterImp {

    public enum State {
        NONE,//无数据
        READING,//正在读
        TIMEOUT,//超时
        FINISHED//识别到头尾
    }

    /**
     * 回调
     */
    @NonNull
    protected final OnCallBack onCallBack;
    protected long timestart = -1;
    /**
     * 超时时间
     */
    public final int timeout;
    @Nullable
    protected byte[] data;
    @NonNull
    protected State mState = State.NONE;

    public ReadByteAdapterAbs(@NonNull OnCallBack callBack) {
        this(100, callBack);
    }

    public ReadByteAdapterAbs(@IntRange(from = 0, to = Integer.MAX_VALUE) int timeout, @NonNull OnCallBack callBack) {
        this.timeout = timeout;
        this.onCallBack = callBack;
    }

    @Override
    public void read(@NonNull byte[] BUFFER, int length) {
        timestart = System.currentTimeMillis();
        setState(State.READING);
        byte[] data = new byte[length];
        System.arraycopy(BUFFER, 0, data, 0, length);
        long current = System.currentTimeMillis();
        long temp = current - timestart;
        if (timeout > 0) {
            if (temp >= timeout) {
                setState(State.TIMEOUT);
                notifyCallbackTimeout(timestart, current, timeout);
                return;
            }
        }
        notifyCallbackRead(data, temp);
        setState(State.FINISHED);
        clear();
    }

    /**
     * @return 是否超时
     */
    protected boolean checkTimeout() {
        long currentTimeMillis;
        if (timestart > 0 && timeout > 0) {
            currentTimeMillis = System.currentTimeMillis();
            if (currentTimeMillis - timestart >= timeout) {
                notifyCallbackTimeout(timestart, currentTimeMillis, timeout);
                setState(State.TIMEOUT);
                clear();
                return true;
            }
        }
        return false;
    }

    /**
     * @param data      数据
     * @param timecount 用时
     */
    protected void notifyCallbackRead(@NonNull final byte[] data, final long timecount) {
        final byte[] DATA = new byte[data.length];
        System.arraycopy(data, 0, DATA, 0, data.length);
        onCallBack.read(DATA, timecount);
    }

    /**
     * @param start   开始接收时间，
     * @param current 当前处理时间
     * @param timeout 超时时间
     */
    protected void notifyCallbackTimeout(final long start, final long current, final int timeout) {
        onCallBack.timeout(start, current, timeout);
    }

    protected void clear() {
        data = null;
        timestart = -1;
    }

    public void setState(@NonNull State state) {
        mState = state;
    }

    @NonNull
    public State getState() {
        return mState;
    }

    public interface OnCallBack {
        void read(@NonNull byte[] data, long time);

        /**
         * @param start   开始
         * @param current 当前
         * @param timeout 超时时间大小
         */
        void timeout(long start, long current, int timeout);
    }
}
